﻿#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "ngx_func.h"
#include "ngx_macro.h"
#include "ngx_c_conf.h"
/***************************************************************
 * @file       ngx_daemon.cxx
 * @brief      守护进程初始化
 * @author     txj
 * @version    v1
 * @return     返回-1，   子进程：返回0，父进程：返回1
 * @date       2021/7/29
 **************************************************************/
int ngx_daemon()
{
    //创建守护进程的第一步，fork()一个子进程出来
    switch (fork())
    {
    case -1:
        //创建子进程失败
        ngx_log_error_core(NGX_LOG_EMERG,errno, "ngx_daemon()中fork()失败!");
        return -1;
    case 0:
        //子进程，走到这里直接break;
        break;
    default:
        //父进程以往 直接退出exit(0);现在希望回到主流程去释放一些资源
        return 1;//父进程直接返回1；
    } 

    //只有fork()出来的子进程才能走到这个流程
    ngx_parent = ngx_pid;
    ngx_pid = getpid();

    //脱离终端，终端关闭，将跟此子进程无关
    if(setsid() == -1)
    {
        ngx_log_error_core(NGX_LOG_EMERG, errno,"ngx_daemon()中setsid()失败!");
        return -1;
    }
    umask(0);
    /*以读写方式打开黑洞设备*/
    int fd = open("/dev/null", O_RDWR);
    if (fd == -1) 
    {
        ngx_log_error_core(NGX_LOG_EMERG,errno,
            "ngx_daemon()中open(\"/dev/null\")失败!");
        return -1;
    }
    /*STDIN_FILENO和STDOUT_FILENO现在的指向
    和fd一样了，即指向黑洞设备了，所以现在如果
    用标准I/O函数进行输入输出看不到了*/
    if(dup2(fd, STDIN_FILENO) == -1) 
    {
        ngx_log_error_core(NGX_LOG_EMERG,errno,
            "ngx_daemon()中dup2(STDIN)失败!");
        return -1;
    }
    if(dup2(fd, STDOUT_FILENO) == -1)
    {
        ngx_log_error_core(NGX_LOG_EMERG,errno,
            "ngx_daemon()中dup2(STDOUT)失败!");
        return -1;
    }
    if(fd > STDERR_FILENO)
    {
        /*释放资源这样这个文件描述符就可以被复用；不然这个数字会被一直占着*/
        if(close(fd) == -1)
        {
            ngx_log_error_core(NGX_LOG_EMERG,errno, 
                "ngx_daemon()中close(fd)失败!");
            return -1;
        }
    }
    return 0;//子进程返回0
}

